08 Spring Data JPA的@Entity注解 您所在的位置:网站首页 jpa 返回指定列 08 Spring Data JPA的@Entity注解

08 Spring Data JPA的@Entity注解

2023-12-18 01:25| 来源: 网络整理| 查看: 265

Spring Data JPA的@Entity注解 基础注解 @Entity

源码

public @interface Entity { // 可选,默认是此实体类的名字,全局唯一 String name() default ""; }

@Entity定义对象将会成为被JPA管理的实体,将映射到指定的数据库表。

@Table

用于指定数据库表的表名

源码

package javax.persistence; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table { // 表的名字,可选。如果不填写,系统认为和实体的名字一样为表名 String name() default ""; // 此表的catalog,可选 String catalog() default ""; // 此表的schema,可选 String schema() default ""; // 唯一性约束,只有创建表的时候有用,默认不需要 UniqueConstraint[] uniqueConstraints() default {}; //索引,只有创建表的时候使用,默认不需要 Index[] indexes() default {}; } @Id

@Id定义属性为数据库的主键,一个实体里面必须有一个

@GeneratedValue

源码

@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface GeneratedValue { // Id的生成策略 GenerationType strategy() default GenerationType.AUTO; // 通过Sequence生成Id,常见的是Oracle数据库Id生成规则,需要配合@SequenceGenerator使用 String generator() default ""; }

GenerationType一共有四个值

public enum GenerationType { // 通过表产生主键,框架由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植 TABLE, // 通过序列产生主键,通过@SequenceGenerator注解指定序列名称,MySQL不支持这种方式 SEQUENCE, // 采用数据库ID自增长,一般用于MYSQL数据库 IDENTITY, // JPA自动选择合适的策略,是默认选项。 AUTO; private GenerationType() { } } @Basic

@Basic表示属性是到数据库表的字段的映射。如果实体的字段没有任何注解,默认即为@Basic

@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Basic { // 可选,EAGER为立即加载,LAZY为延迟加载 FetchType fetch() default FetchType.EAGER; // 可选,设置这个字段是否为null,默认为true boolean optional() default true; } @Transient

@Transient表示该属性并非一个到数据库表字段的映射,表示持久化属性,与@Basic作用相反。JPA映射数据库的时候就会忽略它。

@Column

源码

@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Column { // 数据库中表的列明。可选,默认为与实体属性名保持一样,如果实体属性名中由大写,它会自动分割 String name() default ""; // 是否唯一,默认false,可选 boolean unique() default false; // 数据字段是否允许为空,可选,默认为true boolean nullable() default true; // 执行insert操作的时候是否包含此字段,可选,默认为true boolean insertable() default true; // 执行update的时候是否包含此字段,可选,默认为true boolean updatable() default true; // 表示该字段在数据库中的实际类型 String columnDefinition() default ""; // 数据库字段的长度,可选,默认为255 int length() default 255; } @Temporal

@Temporal用来设置Date类型的属性映射到对应精准的字段。

@Temporal(TemporalType.DATA)映射为日期 --data@Temporal(TemporalType.TIME)映射为日期 --time@Temporal(TemporalType.TIMESTAMP)映射为日期 --data time @Enumerated

@Enumerated很好用,直接映射enum枚举类型的字段

源码

public @interface Enumerated { // 枚举映射的类型,默认为ORDINAL EnumType value() default EnumType.ORDINAL; }

EnumType可选:

ORDINAL:映射枚举的下标SIRING:映射枚举的name

示例:

// 定义一个枚举类 public enum Gender{ MAIL("男性"),FMAIL("女性"); private String value; private Gender(String value){ this.valus = valus; } } //实体类中的使用 @Entity @Table(name = "tb_user") public class User implements Serializable{ @Enumerated(EnumType.STRING) @Column(name = "user_gender") private Gender gender; }

这时插入两条数据,数据库里面的值是MAIL/FMAIL,而不是男性、女性,如果是我们用@Enumerated(EnumType.ORDINAL),那么这时数据库里存储的是0,1。但是实际工作中不建议这样做,因为下标使会发生变化。

@Lob

Lob将属性映射为数据库支持的大对象类型,支持以下两种数据库类型的字段

Clob类型是长字符串类型,java.sql.Clob、Character[]、char[]和String将被映射为Clobl类型Blob类型是字节类型,java.sql.Blob、Byte[]、byte[]和实现了Serializable接口的类型将被映射为Blob类型Clob、Blob占用内存空间较大,一般配合@Basic(fatch=FechType.LAZY)将其设置为延迟加载 关联关系注解 @JoinColumn

定义外键关联的字段名称

public @interface JoinColumn { // 目标表的字段名,必填 String name() default ""; // 本实体的字段名,非必填,默认为本表ID String referencedColumnName() default ""; // 外键字段是否唯一,默认为false boolean unique() default false; // 外键字段是否允许为空,默认为允许 boolean nullable() default true; // 是否跟随一起新增 boolean insertable() default true; // 是否跟随一起修改 boolean updatable() default true; }

用法:主要配合@OneToOne、@ManyToOne、@OneToMany一起使用,但是使用没有意义。

@OneToOne

源码

@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface OneToOne { // 关系目标实体,非必填,默认为该字段的类型 Class targetEntity() default void.class; // cascade 级联操作策略 // PERSIST 级联新建 // REMOVE 级联删除 // REFRESH 级联刷新 // MERGE 级联更新 // ALL 四项权限 CascadeType[] cascade() default {}; // 数据获取方式,立即加载和延迟加载 FetchType fetch() default FetchType.EAGER; // 是否允许为空 boolean optional() default true; // 关联关系被谁维护,非必填,一般不需要特别指定 String mappedBy() default ""; // 是否级联删除,和CascadeType.REMOVE的效果一样,只要配置了两种的一种就会自动级联删除 boolean orphanRemoval() default false; }

用法:@OneToOne需要配合@JoinCloumn一起使用。注意:可以双相关联,也可以只配置一方,需要视需求而定。

示例:假设一个部门只有一个员工

@OneToOne @JoinColumn(name="employee_id",referencedColumnName = "id") private Employee employeeAttribute = new Employee();

employee_id指的是Department里面的字段,而referencedColumnName="id"指的是Employee表里面的字段

如果需要双相关联,Employee的内容如下

@OneToOne(mappedBy = "employeeAttribute") private Department department;

当然不使用mappedBy,和下面效果是一样的

@OneToOne @JoinColumn(name = "id", referencedColumnName = "employee_id") private Employee employeeAttribute = new Employee(); @OneToMany与@ManyToOne

@OneToMany与@ManyToOne可以相对存在,也可以只存在一方

@Entity @Table(name = "user") public class User { @Id private Long id; @OneToMany( cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user" ) private Set setRole; } @Entity @Table(name = "role") public class Role { @Id private Long id; @ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.EAGER ) @JoinColumn(name = "user_id") private User user; } @OrderBy关联查询时排序 public @interface OrderBy { // 要排序的字段,格式如下 // orderby_list::=orderby_item[,orderby_item]* // orderby_item::=[property_or_field_name][ASC|DESC] String value() default ""; }

用法

@Entity @Table(name = "user") public class User { @Id private Long id; @OneToMany( cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user" ) @OrderBy("roleName DESC ") private Set setRole; }

OrderBy中的字段对应的是实体中的名称

@JoinTable

如果对象与对象之间有一个关联关联表的时候,就会用到@JoinTable,一般和@ManyToMany一起使用。

源码:

public @interface JoinTable { // 中间关联关系表名 String name() default ""; // 表的catelog String catalog() default ""; // 表的schema String schema() default ""; // 主链接表的字段 JoinColumn[] joinColumns() default {}; // 被联机的表外键字段 JoinColumn[] inverseJoinColumns() default {}; }

示例:

假设Blog和Tag是多对多的关系,有一个关联关系表blog_tag_relation,表中有两个属性blog_id和tag_id,那么Blog实体里面的写法如下:

@Entity public class Blog { @Id private Long id; @ManyToMany @JoinTable( name = "blog_tag_relation", joinColumns = @JoinColumn(name = "blog_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id") ) private List tags = new ArrayList(); } @ManyToMany

源码

public @interface ManyToMany { Class targetEntity() default void.class; CascadeType[] cascade() default {}; FetchType fetch() default FetchType.LAZY; String mappedBy() default ""; }

@ManyToMany表示多对多,和@OneToOne、@ManyToOne一样也有单向、双向之分。单向双向和注解没有关系,只看实体类之间是否相互引用。

示例:一个博客可以有多个标签,一个标签也可以在多个博客上,Blog和Tag就是多对多的关系

// 单向多对多 @Entity public class Blog { @Id private Long id; @ManyToMany @JoinTable( name = "blog_tag_relation", joinColumns = @JoinColumn(name = "blog_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id") ) private List tags = new ArrayList(); } @Entity public class BlogTagRelation { @Column(name = "blog_id") private Integer blogId; @Column(name = "tag_id") private Integer tag_id; } // 双向多对多 @Entity public class Blog { @Id private Long id; @ManyToMany(cascade=CascadeType.ALL) @JoinTable( name = "blog_tag_relation", joinColumns = @JoinColumn(name = "blog_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id") ) private List tags = new ArrayList(); } @Entity public class Tag { @Id private String id; @ManyToMany(mappedBy = "BlogTagRelation") private List blog = new ArrayList(); } @EntityGraph

JPA2.1推出的@EnttiyGraph、@NamedEntityGraph用来提高查询效率,很好地解决了N+1条SQL的问题。两者配合起来使用,缺一不可。

1、现在Entity里面定义@NamedEntityGraph,其他不变,其中,@NamedAttributeNode可以有多个,也可以有一个

@NamedEntityGraph( name = "UserInfoEntity.addressEntityList", attributeNodes = { @NamedAttributeNode("addressEntityList"), @NamedAttributeNode("userBlogEntityList") }) @Entity(name = "UserInfoEntity") @Table(name = "user_info", schema = "test") public class UserInfoEntity implements Serializable { @Id @Column(name = "id", nullable = true) private Integer id; @OneToOne(optional = true) @JoinColumn( referencedColumnName = "id", name = "address_id", nullable = false ) private UserReceivingAddressEntity addressEntityList; @OneToMany @JoinColumn(name = "create_user_id", referencedColumnName = "id") private List userBlogEntityList; }

2、只需要在查询方法上加@EntityGraph注解即可,其中value就是@NamedEntityGraph中的name。

public interface UserRepository extends JpaRepository { @Override @EntityGraph(value = "UserInfoEntity.addressEntityList") List findAll(); } 关于关系查询的一些坑

1、所有的注解要么配置在字段上,要么配置在get方法上,不要混用

2、所有的关联都是支持单向关联和双相关联的。JSON序列化的时候双向注解会产生死循环,需要人为手动转化一次,或者使用@JsonIgnore

3、在所有的关联查询中,表一般是不需要建立外键索引

4、级联删除比较危险,建议考虑清楚,或者完全掌握

5、不同的关联关系的设置,@JoinCloum里面的name、referencedCloumName代表的意思是不一样的,很容易混淆,可以根据打印出来的sql调整

6、当配置这些关联关系的时候建议直接在表上面,把外键建好,然后通过工具生成,这样可以减少调试的时间



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有